package com.ipan.builder.db;

import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.List;

import org.hibernate.cfg.Environment;
import org.hibernate.cfg.JDBCMetaDataConfiguration;
import org.hibernate.cfg.Settings;
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.mapping.Table;
import org.hibernate.tool.hbm2x.Hbm2DDLExporter;
import org.hibernate.tool.hbm2x.POJOExporter;
import org.hibernate.tool.ipan.reveng.DatabaseReverser;
import org.hibernate.tool.ipan.reveng.IDatabaseReverser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ipan.builder.BuilderCfg;
import com.ipan.builder.db.comment.BaseCommentOp;
import com.ipan.builder.db.comment.CommentOp;
import com.ipan.builder.entity.EntityOpUtils;
import com.ipan.builder.entity.JpaEntityCfg;

/**
 * 数据库操作基类
 * 
 * @author iPan
 * @version 2013-12-19
 */
public abstract class AbstractDataBaseOp implements DatabaseOp {

	protected JDBCMetaDataConfiguration configuration;
	protected Settings settings;
	protected ConnectionProvider connectionProvider;
	protected CommentOp commentOp;
	protected IDatabaseReverser reverser;
	protected Logger logger = LoggerFactory.getLogger(getClass());

	public AbstractDataBaseOp() {
		this.configuration = createConfiguration();
		this.settings = configuration.buildSettings(); // 需要连接数据库，所以需要保存；
		this.connectionProvider = settings.getConnectionProvider();
		this.commentOp = BaseCommentOp.createCommentOpByDialect(settings.getDialect(), this);
		JDBCMetaDataConfiguration configuration2 = createConfiguration();
		this.reverser = DatabaseReverser.createDatabaseReverser(configuration2, true);
	}

	public JDBCMetaDataConfiguration getConfiguration() {
		return configuration;
	}

	public Settings getSettings() {
		return settings;
	}
	
	public IDatabaseReverser getReverser() {
		return reverser;
	}

	public void updateComment(JpaEntityCfg entityCfg) {
		commentOp.updateAll(entityCfg);
	}
	
	public void updateComment(List<JpaEntityCfg> entityCfgList) {
		if (entityCfgList == null || entityCfgList.size() < 1) {
			return ;
		}
		for (JpaEntityCfg entityCfg : entityCfgList) {
			commentOp.updateAll(entityCfg);
		}
	}
	
	public void updateAllComment() {
		updateComment(EntityOpUtils.loadJpaEntityCfgList());
	}

	public String getSchemaName() {
		return settings.getDefaultSchemaName();
	}

	public String getCatalogName() {
		return settings.getDefaultCatalogName();
	}
	
	/**
	 * 获取Connection
	 */
	public Connection getConnection() {
		Connection conn = null;
		try {
			conn = connectionProvider.getConnection();
		} catch (SQLException e) {
			throwJDBCException(e);
		}
		return conn;
	}

	/**
	 * 执行SQL
	 */
	public void execute(String sql, Object[] params) {
		Connection conn = null;
		PreparedStatement statement = null;
		try {
			conn = getConnection();
			statement = conn.prepareStatement(sql);
			fillStatement(statement, params);
			logger.info(sql);
			statement.execute(sql);
		} catch (SQLException e) {
			throwJDBCException(e, sql, params);
		} finally {
			closeConnection(conn);
			closeStatement(statement);
		}
	}

	/**
	 * 关闭Connection
	 */
	public void closeConnection(Connection conn) {
		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				logger.warn("close Connection error.", e);
			}
		}
	}

	/**
	 * 关闭Statement
	 */
	public void closeStatement(Statement statement) {
		if (statement != null) {
			try {
				statement.close();
			} catch (SQLException e) {
				logger.warn("close Statement error.", e);
			}
		}
	}

	/**
	 * 关闭ResultSet
	 */
	public void closeResultSet(ResultSet resultSet) {
		if (resultSet != null) {
			try {
				resultSet.close();
			} catch (SQLException e) {
				logger.warn("close ResultSet error.", e);
			}
		}
	}

	/**
	 * 抛出异常JDBCException
	 */
	public void throwJDBCException(Exception e) {
		throw new JDBCException(e);
	}

	/**
	 * 抛出异常JDBCException
	 */
	public void throwJDBCException(SQLException e, String sql, Object[] params) {
		throw new JDBCException(e, sql, params);
	}

	/**
	 * 填充PreparedStatement参数
	 */
	public void fillStatement(PreparedStatement stmt, Object[] params) {
		if (params == null || params.length < 1) {
			return;
		}
		try {
			for (int i = 0; i < params.length; ++i) {
				if (params[i] != null) {
					stmt.setObject(i + 1, params[i]);
				} else {
					stmt.setNull(i + 1, Types.CHAR);
				}
			}
		} catch (SQLException e) {
			throwJDBCException(e);
		}
	}
	
	protected void doExportPojo() {
		File file = new File(configuration.getReverseEngineeringStrategy().getSettings().getExportDir());
		POJOExporter pojoExporter = new POJOExporter(configuration, file);
		pojoExporter.start();
	}
	
	protected void doExportDdl(String fileName) {
		File file = new File(configuration.getReverseEngineeringStrategy().getSettings().getExportDir());
		Hbm2DDLExporter hbm2ddlExporter = new Hbm2DDLExporter(configuration, file);
		hbm2ddlExporter.setFormat(true);
		hbm2ddlExporter.setOutputFileName(fileName);
		hbm2ddlExporter.setCreate(true);
		hbm2ddlExporter.setDrop(true);
		hbm2ddlExporter.setExport(false);
		hbm2ddlExporter.setUpdate(false);
		hbm2ddlExporter.start();
	}
	
	public JDBCMetaDataConfiguration createConfiguration() {
		JDBCMetaDataConfiguration cfg = JDBCMetaDataConfiguration.createByPropertiesClasspath(BuilderCfg.CONFIG_FILE);
		// 使用不带连接池的链接管理器
		// Connection关闭交给外部，因为使用默认连接池的话关闭链接就是个问题了；
		cfg.setProperty(Environment.CONNECTION_PROVIDER, "org.hibernate.tool.ipan.connection.NoPoolConnectionProvider");
		return cfg;
	}
	
	protected Table[] getAllTables() {
		reverser.flush();
		Table[] allTable = reverser.getAllTable();
		return allTable;
	}
	
}
